//////////////////////////////////////////////
// File				:	Keyboard.cpp
//
// Author			:	Nick Faletra (NF)
//
// Date Created		:	12/20/2013
//////////////////////////////////////////////
#include "Keyboard.h"

CKeyboard::CKeyboard(IDirectInput8* pDI, HWND hWnd, bool bExclusive)
{
	if (FAILED(pDI->CreateDevice(GUID_SysKeyboard, &m_pDevice, nullptr)))
		DIERRBOX(hWnd, "Failed to create Keyboard device.");

	if (FAILED(m_pDevice->SetDataFormat(&c_dfDIKeyboard)))
		DIERRBOX(hWnd, "Failed to set data format on Keyboard.");

	DWORD dwFlags = DISCL_FOREGROUND;

	dwFlags |= bExclusive ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE | DISCL_NOWINKEY;

	if (FAILED(m_pDevice->SetCooperativeLevel(hWnd, dwFlags)))
		DIERRBOX(hWnd, "Failed to set cooperative level on Keyboard.");

	DIPROPDWORD dipdw;

	memset(&dipdw, 0, sizeof(DIPROPDWORD));
	dipdw.diph.dwSize = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj = 0;
	dipdw.diph.dwHow = DIPH_DEVICE;
	dipdw.dwData = BUFFER_SIZE;

	if (FAILED(m_pDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
		DIERRBOX(hWnd, "Could not Set the Properties for Buffered Input for Keyboard.");

	if (FAILED(m_pDevice->Acquire()))
		DIERRBOX(hWnd, "Failed to acquire Keyboard.");

	ClearKeys();

	m_keyLayout = GetKeyboardLayout(0);
}

void CKeyboard::ClearKeys()
{
	memset(m_ucKeysPressed, 0, 256 * sizeof(unsigned char));
	memset(m_ucPrevKeysPressed, 0, 256 * sizeof(unsigned char));
}

bool CKeyboard::ReadDevice()
{
	if (!m_pDevice)
		return false;

	memcpy(m_ucPrevKeysPressed, m_ucKeysPressed, sizeof(m_ucPrevKeysPressed));

	if (FAILED(m_pDevice->GetDeviceState(sizeof(m_ucKeysPressed), (void*)m_ucKeysPressed)))
	{
		if (FAILED(m_pDevice->Acquire()))
			return false;

		if (FAILED(m_pDevice->GetDeviceState(sizeof(m_ucKeysPressed), (void*)m_ucKeysPressed)))
			return false;
	}

	return true;
}

bool CKeyboard::ReadBufferedDevice()
{
	if (!m_pDevice)
		return false;

	ClearBufferedData();

	if (FAILED(m_pDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0)))
	{
		if (FAILED(m_pDevice->Acquire()))
			return false;

		ClearBufferedData();

		if (FAILED(m_pDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0)))
			return false;
	}

	return false;
}

bool CKeyboard::KeyDown(unsigned char ucDIKey)
{
	return (m_ucKeysPressed[ucDIKey] & 0x80) ? true : false;
}

bool CKeyboard::KeyPressed(unsigned char ucDIKey)
{
	return KeyDown(ucDIKey) && !(m_ucPrevKeysPressed[ucDIKey] & 0x80);
}

bool CKeyboard::KeyPressedEx(unsigned char ucDIKey)
{
	for (unsigned int i = 0; i < m_dwBufferElements; ++i)
		if ((m_didod[i].dwOfs == ucDIKey) && (m_didod[i].dwData & 0x80))
			return true;

	return false;
}

bool CKeyboard::KeyUp(unsigned char ucDIKey)
{
	return !KeyDown(ucDIKey);
}

bool CKeyboard::KeyReleased(unsigned char ucDIKey)
{
	return KeyUp(ucDIKey) && (m_ucPrevKeysPressed[ucDIKey] & 0x80);
}

bool CKeyboard::KeyReleasedEx(unsigned char ucDIKey)
{
	for (unsigned int i = 0; i < m_dwBufferElements; ++i)
		if ((m_didod[i].dwOfs == ucDIKey) && !(m_didod[i].dwData & 0x80))
			return true;

	return false;
}

char CKeyboard::CheckKeys()
{
	if (!GetKeyboardState(m_ucAsciiVals))
		return 0;

	unsigned short num = 0;
	unsigned int VKCode = 0;

	for (int i = 0; i < 256; ++i)
	{
		if (KeyDown((unsigned char)i))
		{
			VKCode = MapVirtualKeyEx(i, 1, m_keyLayout);
			ToAsciiEx(VKCode, i, m_ucAsciiVals, &num, 0, m_keyLayout);
		}
	}

	return (char)num;
}

char CKeyboard::CheckBufferedKeysEx()
{
	if (!GetKeyboardState(m_ucAsciiVals))
		return 0;

	unsigned short num = 0;
	unsigned int VKCode = 0;

	for (unsigned int i = 0; i < m_dwBufferElements; ++i)
	{
		for (unsigned int j = 0; j < 256; ++j)
		{
			if (m_didod[i].dwOfs == j && m_didod[i].dwData & 0x80)
			{
				VKCode = MapVirtualKeyEx(m_didod[i].dwOfs, 1, m_keyLayout);
				ToAsciiEx(VKCode, m_didod[i].dwOfs, m_ucAsciiVals, &num, 0, m_keyLayout);
			}
		}
	}

	return (char)num;
}

unsigned char CKeyboard::GetDIKCode()
{
	unsigned char num = 0;

	for (unsigned char i = 0; i < 256; ++i)
	{
		if (KeyDown(i))
		{
			num = i;
			break;
		}
	}

	return num;
}

unsigned char CKeyboard::GetBufferedDIKCodeEx()
{
	unsigned char num = 0;

	for (unsigned int i = 0; i < m_dwBufferElements; ++i)
	{
		for (unsigned int j = 0; j < 256; ++j)
		{
			if (m_didod[i].dwOfs == j && m_didod[i].dwData & 0x80)
			{
				num = (unsigned char)j;
				break;
			}
		}
	}

	return num;
}